package cn.mrlong.tools.view

import java.awt.BorderLayout
import java.awt.Dimension
import java.awt.Graphics
import java.awt.Point
import javax.swing.JPanel
import javax.swing.JScrollPane
import javax.swing.JTextArea
import javax.swing.text.BadLocationException

/**
 * @ClassName MyTextArea
 * @Description 实现 JTextArea 显示行号
 * @Author Li
 * @Date 2022/8/28 13:55
 * @ModifyDate 2022/8/28 13:55
 * @Version 1.0
 */
class MyTextArea : JPanel() {
    private val linePanel: LinePanel

    private val textArea: JTextArea

    private val scrollPane: JScrollPane

    init {
        this.layout = BorderLayout()
        linePanel = LinePanel()
        linePanel.preferredSize = Dimension(25, 10)
        this.textArea = object : JTextArea() {
            override fun paint(g: Graphics) {
                super.paint(g)
                linePanel.repaint()
            }
        }
        this.scrollPane = JScrollPane(this.textArea)
        this.add(linePanel, BorderLayout.WEST)
        this.add(scrollPane, BorderLayout.CENTER)
    }

    // 内部类：显示行号的面板
    private inner class LinePanel : JPanel() {
        override fun paint(g: Graphics) {
            super.paint(g)
            // starting pos in document
            val start = textArea.viewToModel(scrollPane.viewport.viewPosition)
            // end pos in doc
            val end = textArea.viewToModel(
                Point(
                    scrollPane.viewport.viewPosition.x + textArea.width,
                    scrollPane.viewport.viewPosition.y + textArea.height
                )
            )

            // translate offsets to lines
            val doc = textArea.document
            val startLine = doc.defaultRootElement.getElementIndex(start) + 1
            val endLine = doc.defaultRootElement.getElementIndex(end) + 1

            val fontHeight = g.getFontMetrics(textArea.font).height
            val fontDesc = g.getFontMetrics(textArea.font).descent
            var starting_y = -1

            try {
                starting_y = textArea.modelToView(start).y -
                        scrollPane.viewport.viewPosition.y + fontHeight - fontDesc
            } catch (ble: BadLocationException) {
                ble.printStackTrace()
            }

            run {
                var line = startLine
                var y = starting_y
                while (line <= endLine) {
                    g.drawString(line.toString(), getNumX(line), y)
                    y += fontHeight
                    line++
                }
            }
        }

        // 获取当前行的行号 x 坐标
        private fun getNumX(line: Int): Int {
            var line = line
            val width = linePanel.width - 5
            val metrics = linePanel.getFontMetrics(this.font)
            val fontHeight = metrics.height
            val fontWidth = metrics.stringWidth("0")
            var digit = 0
            while (line > 0) {
                line = line / 10
                digit++
            }
            val x = width - digit * fontWidth
            // 自适应调整宽度
            if (x < 5) {
                linePanel.preferredSize = Dimension(getWidth() + fontWidth, fontHeight)
                linePanel.updateUI()
            }
            return x
        }
    }
}